<template>
  <div class="dom-list">
    <el-input v-model="input" placeholder="输入你想干的事" @keydown.enter="addThing">
      <template #append><el-button @click="addThing">添加</el-button></template>
    </el-input>

    <div style="margin: 10px 0;">我爱干的事情</div>
    <ul>
      <li v-for="item in todoList">{{item}}</li>
    </ul>

    <h1 class="my-title" id="slot1">Provide & Inject</h1>
    <el-divider content-position="left">案例区域(组件页面上的效果)</el-divider>
    <div>
      <subTodo></subTodo>
    </div>
    <el-divider>代码分析区域</el-divider>
    <p class="note-text">先在父级定义provide，在去孙子组件里定义inject。</p>
    <el-divider content-position="left">组件使用(父组件里调用孙子subTodo组件)</el-divider>
    <code-beautify :htmlCode="codeData.code1" isTitle></code-beautify>
    <code-beautify :jsCode="codeData.code2" isTitle></code-beautify>
    <el-divider content-position="left"> subTodo 组件中的代码</el-divider>
    <code-beautify :htmlCode="codeData.code3" isTitle></code-beautify>
    <code-beautify :jsCode="codeData.code4" isTitle></code-beautify>
    <el-divider content-position="left">其它使用场景</el-divider>
    <p class="note-text">如果需要使用父组件里的字段，需要将父组件中的 provide 转换为返回对象的函数。</p>
    <code-beautify :jsCode="codeData.code5"></code-beautify>
    <h2 class="my-sub-title">处理响应式的数据。</h2>
    <p class="note-text">默认情况下，provide/inject 绑定并不是响应式的，如果我们想对祖先组件中的更改做出响应，我们需要为 provide 的 todoLength 分配一个组合式 API computed property，如下：</p>
    <code-beautify :jsCode="codeData.code6"></code-beautify>

    <h1 class="my-title">使用setup方式使用Provide & Inject</h1>
    <p class="note-text">在 setup() 中使用 provide 时，我们首先从 vue 显式导入 provide 方法。这使我们能够调用 provide 来定义每个 property。</p>
    <code-beautify :jsCode="setupCodeData.code1"></code-beautify>
    <p class="note-text">在 setup() 中使用 inject 时，也需要从 vue 显式导入。导入以后，我们就可以调用它来定义暴露给我们的组件方式。</p>
    <code-beautify :htmlCode="setupCodeData.code2" isTitle></code-beautify>
    <code-beautify :jsCode="setupCodeData.code3" isTitle></code-beautify>
    <h2 class="my-sub-title">setup() 中处理响应式的数据。</h2>
    <p class="note-text">为了增加 provide 值和 inject 值之间的响应性，我们可以在 provide 值时使用 ref 或 reactive。</p>
    <code-beautify :jsCode="setupCodeData.code4"></code-beautify>
    <code-beautify :jsCode="setupCodeData.code5"></code-beautify>
  </div>
</template>

<script>
  import subTodo from '@/components/ProvideOrInject/todo.vue'
  import { ref, computed, provide, reactive, readonly, onMounted } from 'vue'
  import {css_beautify, html_beautify} from "js-beautify"

  export default {
    name: "ProvideOrInject",
    components: {
      subTodo
    },
    provide() {
      return {
        user: 'wen hui',
        length: computed(() => this.todoList.length)
      }
    },
    setup() {
      const codeData = ref({})
      const setupCodeData = ref({})
      const input = ref('')
      const todoList = ref([])
      // let my = ref('')

      todoList.value = ['喝茶', '吃饭', '睡觉']

      // provide('name', '温慧')
      // provide('info', {
      //   age: 90,
      //   sex: '男'
      // })

      const name = ref('温慧')
      const my = ref(todoList.value[todoList.value.length-1])
      const info = reactive({
        age: 90,
        sex: '男',
        my
      })

      provide('name', readonly(name))
      provide('info', info)
      provide('addThing', addThing)

      onMounted(() => {
        codeData.value.code1 = html_beautify('<subTodo></subTodo>', {indent_size: 2, space_in_empty_paren: true})
        codeData.value.code2 = css_beautify('provide: {user: \'温慧\'}', {indent_size: 2, space_in_empty_paren: true})
        codeData.value.code3 = html_beautify('<template><p>我是来自上一级的上一级传过来的数据</p><p>我不是来自props里的数据</p> <p>我叫：{{user}}，来自父级的父级中的provide里定义的user，我的爱好有：{{length}}种</p></template>', {indent_size: 2, space_in_empty_paren: true})
        codeData.value.code4 = css_beautify('inject: [\'user\']', {indent_size: 2, space_in_empty_paren: true})
        codeData.value.code5 = css_beautify('provide() {return {user: \'wen hui\',length: this.todoList.length}', {indent_size: 2, space_in_empty_paren: true})
        codeData.value.code6 = css_beautify('provide() {return {user: \'wen hui\',length: computed(() => this.todoList.length)}', {indent_size: 2, space_in_empty_paren: true})

        setupCodeData.value.code1 = css_beautify('import { ref, computed, provide, onMounted } from \'vue\';setup() {provide(\'name\', \'温慧\');provide(\'info\', {age: 90,sex: \'男\'})}', {indent_size: 2, space_in_empty_paren: true})
        setupCodeData.value.code2 = html_beautify('<template><p>我是以setup的方式来传递数据的</p><p>我的中文名是：{{name}}，我的年龄是：{{info.age}}，我的性别是：{{info.sex}}</p></template>', {indent_size: 2, space_in_empty_paren: true})
        setupCodeData.value.code3 = css_beautify('import {inject} from \'vue\';setup() {const name = inject(\'name\');const info = inject(\'info\');return{name,info}}', {indent_size: 2, space_in_empty_paren: true})
        setupCodeData.value.code4 = css_beautify('import { ref, computed, provide,reactive, onMounted } from \'vue\';setup() {const name = ref(\'North Pole\');const my = ref(todoList.value[todoList.value.length-1]);const info = reactive({age: 90,sex: \'男\',my});provide(\'name\', name);provide(\'info\', info);function addThing() {todoList.value.push(input.value);my.value = todoList.value[todoList.value.length-1];}}', {indent_size: 2, space_in_empty_paren: true})
      })

      async function addThing(val) {
        if (typeof(val) === 'string') {
          my.value = val
        } else {
          todoList.value.push(input.value)
          my.value = todoList.value[todoList.value.length-1]
        }
      }

      return {
        codeData,
        setupCodeData,
        input,
        todoList,
        addThing
      }
    }
  }
</script>

<style scoped>

</style>
